package vca;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

import org.jgrapht.alg.DijkstraShortestPath;

import jenes.algorithms.IslandGA.Graph;
import jenes.chromosome.IntegerChromosome;
import jenes.population.Individual;

public class Enviroment {

	public final static int OBSTACLE = 2;
	public final static int BASE = 3;
	public final static int CLEAN = 0;
	public final static int DIRTY = 1;
	public static int SUCK_COST = 1;
	protected static int DIRTY_TILES_NUMBER = 53;
	private int[][] matrix;
	private ArrayList<Point> dt;
	private Point base;
	private Point agentInitialPosition;
	private int populationSize;
	private int genationSize;
	private GraphManager manager;
	protected static int INITIAL_ENERGY;

	public Enviroment(int[][] matrix, ArrayList<Point> dt, Point base,
			Point agentInitialPostion, int populationSize, int genationSize,
			int initialEnergy) {
		INITIAL_ENERGY = initialEnergy;
		this.matrix = matrix;
		this.dt = dt;
		this.base = base;
		this.agentInitialPosition = agentInitialPostion;
		this.populationSize = populationSize;
		this.genationSize = genationSize;

		manager = new GraphManager(this.matrix, this.getDt(), this.base,
				this.agentInitialPosition);
		DIRTY_TILES_NUMBER = manager.pruneDirtyNodes();
		this.dt = manager.dirtyTiles; // aggiornamento dopo potatura
	}

	public Solution greedyAlgorithm() {

		ArrayList<Point> tmpDirty = (ArrayList<Point>) getDt().clone();

		Point current = agentInitialPosition;

		int tmp = 0;

		int energy = INITIAL_ENERGY;

		ArrayList<Integer> indexes = new ArrayList<>();

		int min = Integer.MAX_VALUE;

		while (tmpDirty.size() != indexes.size()) {
			for (int i = 0; i < tmpDirty.size(); i++) {
				if (tmpDirty.get(i) == null)
					continue;
				List l = DijkstraShortestPath.findPathBetween(manager.graph,
						current, tmpDirty.get(i));
				if (l.size() < min) {
					min = l.size();
					tmp = i;
				}
			}

			energy = energy - min - SUCK_COST;
			List l = DijkstraShortestPath.findPathBetween(manager.graph,
					tmpDirty.get(tmp), base);

			if (energy < l.size())
				break;

			current = tmpDirty.get(tmp);
			tmpDirty.set(tmp, null);
			indexes.add(tmp);
			min = Integer.MAX_VALUE;
		}

		Solution s = new Solution();

		ArrayList<Point> path = manager.computePath(indexes);

		s.actions = writeActions(indexes, path);

		final double ET = (Enviroment.INITIAL_ENERGY - (path.size()-1) - SUCK_COST
				* indexes.size());
		final double BdT = 0;
		final double E0 = INITIAL_ENERGY;
		final double CT = indexes.size();
		final double D0 = DIRTY_TILES_NUMBER;

		
		final Double performanceMeasure = Math.ceil((ET - BdT + 1) / (E0 + 1))
				* (CT + 1) / (D0 + 1) * (1 + (ET + 1) / (E0 + 1));

		s.performanceMesure = performanceMeasure;

		// System.out.println(s.peformanceMesure);
		// System.out.println(s.actions);

		return s;
	}

	public Solution geneticAlgorithm() {

		GA ga = new GA(manager, DIRTY_TILES_NUMBER, populationSize,
				genationSize);
		Individual<IntegerChromosome> solution = ga.execute();

		ArrayList<Integer> indexes = new ArrayList<>();
		for (int i = 0; i < solution.getChromosomeLength(); i++) {
			if (solution.getChromosome().getValue(i) != -1)
				indexes.add(solution.getChromosome().getValue(i));
		}
		// ArrayList<Point> path = manager.computePath(indexes);
		// ArrayList<String> actions = writeActions(indexes, path);

		Solution s = new Solution();

		ArrayList<Point> path = manager.computePath(indexes);

		s.actions = writeActions(indexes, path);

		// double f = ((manager.matrixSize * manager.matrixSize * 2)
		// * (manager.initalCleanTiles + indexes.size()) +
		// (Enviroment.INITIAL_ENERGY - path
		// .size()-SUCK_COST*indexes.size()));
		// f = f
		// / (2 * Math.pow(manager.matrixSize, 4) + Enviroment.INITIAL_ENERGY);

		s.performanceMesure = solution.getScore();

		// System.out.println(s.peformanceMesure);
		// System.out.println(s.actions);

		return s;
	}

	private ArrayList<String> writeActions(ArrayList<Integer> indexes,
			ArrayList<Point> path) {
		ArrayList<String> actions = new ArrayList<>();
		int indexDirty = 0;
		for (int i = 1; i < path.size(); i++) {
			Point prec = path.get(i - 1);
			Point succ = path.get(i);
			int diffRiga = succ.x - prec.x;
			int diffCol = succ.y - prec.y;

			if (diffRiga == 0) {
				if (diffCol == 1)
					actions.add("right");
				else
					actions.add("left");
			} else {
				if (diffRiga == 1)
					actions.add("down");
				else
					actions.add("up");
			}

			if (indexDirty < indexes.size()
					&& path.get(i).equals(getDt().get(indexes.get(indexDirty)))) {
				actions.add("suck");
				indexDirty++;
			}

		}
		return actions;
	}

	public boolean isBaseReachable() {
		GraphManager manager = new GraphManager(matrix, getDt(), base,
				agentInitialPosition);
		return manager.baseIsReachable();
	}

	public static void main(String[] args) {

		// int[][] matrix = { { 0, 0, 0, 0, 0, 0, 0, 0 },
		// { 0, 1, 1, 1, 2, 2, 1, 0 }, { 0, 1, 1, 1, 1, 2, 1, 0 },
		// { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 3, 0, 0, 0 },
		// { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 },
		// { 0, 0, 0, 0, 0, 0, 0, 0 } };
		//
		// ArrayList<Point> dt = new ArrayList<Point>();
		//
		// for (int i = 0; i < matrix[0].length; i++)
		// for (int j = 0; j < matrix[0].length; j++)
		// if (matrix[i][j] == 1)
		// dt.add(new Point(i, j));
		// Enviroment ev = new Enviroment(matrix, dt, new Point(4, 4), 100, 100,
		// 100);

		// System.out.println(ev.getActions());
		// ev.greedyAlgorithm();
		// ev.geneticAlgorithm();
		// GraphManager manager = new GraphManager(matrix, dt, new Point(2, 3));
		//
		// DIRTY_TILES_NUMBER = manager.pruneDirtyNodes();
		//
		// dt = manager.dirtyTiles;
		//
		// GA ga = new GA(manager, DIRTY_TILES_NUMBER, 100, 100);
		// Individual<IntegerChromosome> solution = ga.execute();
		//
		// ArrayList<Integer> indexes = new ArrayList<>();
		// for (int i = 0; i < solution.getChromosomeLength(); i++) {
		// if (solution.getChromosome().getValue(i) != -1)
		// indexes.add(solution.getChromosome().getValue(i));
		// }
	}

	public ArrayList<Point> getDt() {
		return dt;
	}

}
